package com.edushare.common.dao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.query.SelectQuery;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.edushare.common.orm.ORMInterface;
import com.edushare.common.vo.Courses;
import com.edushare.common.vo.Curricula;
import com.edushare.common.vo.Departments;
import com.edushare.common.vo.ElectivePreference;
import com.edushare.common.vo.SemesterCourses;
import com.edushare.common.vo.Universities;

public class CurriculumDAO extends CayenneBasedDAO {
	public CurriculumDAO(ORMInterface ormInterface) {
		super(ormInterface);
	}

	private static Log log = LogFactory.getLog(CurriculumDAO.class);

	public Curricula getCurriculaById(int pk) {
		Curricula curr = null;
		Expression exp = Expression.fromString("curriculaId = $currId");
		HashMap<String, Integer> params = new HashMap<String, Integer>();
		params.put("currId", pk);
		SelectQuery query = new SelectQuery(Curricula.class, exp
				.expWithParameters(params));
		List<?> lst = getDataContext().performQuery(query);
		if (lst != null && lst.size() > 0)
			curr = (Curricula) lst.get(0);
		return curr;
	}

	public Curricula newCurriculum(String curriculaName,
			Departments department, Integer totalSemester) {
		Curricula curr = new Curricula();
		curr.setCurriculaDesc("");
		curr.setCurriculaName(curriculaName);
		curr.setDepartment(department);
		curr.setTotalSemester(totalSemester);
		curr.setUniversity(new DepartmentsDAO(ormInterface)
				.getParent(department));

		getDataContext().registerNewObject(curr);
		getDataContext().commitChanges();
		return curr;
	}

	public void addMandatoryCourse(Curricula curr, List<Courses> courseList,
			int sem) {
		for (Courses c : courseList) {
			addMandatoryCourse(curr, c, sem);
		}
	}

	public void addMandatoryCourse(Curricula curr, Courses course, int sem) {
		removeMandatoryCourse(curr, course, sem);
		SemesterCourses semCourse = new SemesterCourses();
		semCourse.setCourseType(SemesterCourses.MANDATORY_COURSE);
		semCourse.setCourse(course);
		semCourse.setCurricula(curr);
		semCourse.setElectiveGroup(0);
		semCourse.setParentSemCourse(null);
		semCourse.setSemesterNo(sem);

		getDataContext().registerNewObject(semCourse);
		getDataContext().commitChanges();
	}

	public void removeMandatoryCourse(Curricula curr, Courses course, int sem) {
		List<SemesterCourses> semList = curr.getSemesterCourses();
		SemesterCourses deleteObj = null;
		for (SemesterCourses s : semList) {
			if (s.getSemesterNo() == sem && s.getCourse() == course) {
				deleteObj = s;
			}
		}
		if (deleteObj == null)
			return;
		getDataContext().deleteObject(deleteObj);
		getDataContext().commitChanges();
	}

	public void addElectiveChoices(Curricula curr, List<Courses> courseList,
			int sem) {
		SemesterCourses semCourse = new SemesterCourses();
		Integer groupId = getNumElectives(curr, sem);
		semCourse.setCourseType(SemesterCourses.ELECTIVE_COURSE);
		semCourse.setCurricula(curr);
		semCourse.setSemesterNo(sem);
		semCourse.setCourse(courseList.get(0));
		semCourse.setParentSemCourse(null);
		semCourse.setElectiveGroup(groupId);
		getDataContext().registerNewObject(semCourse);

		for (Courses courses : courseList) {
			SemesterCourses semCourse1 = new SemesterCourses();
			semCourse1.setCourseType(SemesterCourses.ELECTIVE_COURSE);
			semCourse1.setCurricula(curr);
			semCourse1.setSemesterNo(sem);
			semCourse1.setCourse(courses);
			semCourse1.setElectiveGroup(groupId);
			semCourse1.setParentSemCourse(semCourse);
			getDataContext().registerNewObject(semCourse1);
		}
		getDataContext().commitChanges();
	}

	public Curricula changeDept(Curricula curr, Departments dept) {
		curr.setDepartment(dept);
		getDataContext().commitChanges();
		return curr;
	}

	public Curricula changeName(Curricula curr, String name) {
		curr.setCurriculaName(name);
		getDataContext().commitChanges();
		return curr;
	}

	public Curricula changeSemNum(Curricula curr, int semNum) {
		curr.setTotalSemester(semNum);
		getDataContext().commitChanges();
		return curr;
	}

	public void clearMandatoryCourses(Curricula curr, int sem) {
		List<SemesterCourses> semCourses = curr.getSemesterCourses();
		List<SemesterCourses> toDelete = new ArrayList<SemesterCourses>();
		for (SemesterCourses s : semCourses) {
			if (s.getSemesterNo() == sem
					&& s.getCourseType() == SemesterCourses.MANDATORY_COURSE){
				clearElectiveChoices(s);
				toDelete.add(s);
			}
		}
		getDataContext().deleteObjects(toDelete);
		getDataContext().commitChanges();
	}
	
	public void clearElectiveChoices(SemesterCourses sc){
		List<ElectivePreference> epL = sc.getPreferences();
		getDataContext().deleteObjects(epL);
	}

	public void clearOptionalCourses(Curricula curr, int sem) {
		List<SemesterCourses> semCourses = curr.getSemesterCourses();
		List<SemesterCourses> deleteChildren = new ArrayList<SemesterCourses>();
		List<SemesterCourses> deleteParents = new ArrayList<SemesterCourses>();
		for (SemesterCourses s : semCourses) {
			if (s.getSemesterNo() == sem && s.getParentSemCourse() == null){
				clearElectiveChoices(s);
				deleteParents.add(s);
			}
			else if (s.getSemesterNo() == sem){
				clearElectiveChoices(s);
				deleteChildren.add(s);
			}
		}
		getDataContext().deleteObjects(deleteChildren);
		getDataContext().deleteObjects(deleteParents);
		getDataContext().commitChanges();
	}

	public List<Courses> getMandatoryCourses(Curricula curr, int sem) {
		List<Courses> courseList = new ArrayList<Courses>();
		List<SemesterCourses> semList = curr.getSemesterCourses();
		for (SemesterCourses s : semList) {
			if (s.getSemesterNo() == sem
					&& s.getCourseType() == SemesterCourses.MANDATORY_COURSE
					&& s.getParentSemCourse() == null)
				courseList.add(s.getCourse());
		}
		return courseList;
	}

	public List<List<Courses>> getOptionalCourses(Curricula curr, int sem) {
		List<List<Courses>> superList = new ArrayList<List<Courses>>();
		List<SemesterCourses> sList = curr.getSemesterCourses();
		for (SemesterCourses s : sList) {
			if (s.getSemesterNo() == sem
					&& s.getCourseType() == SemesterCourses.ELECTIVE_COURSE
					&& s.getParentSemCourse() == null) {
				List<Courses> courseList = new ArrayList<Courses>();
				List<SemesterCourses> childrenL = s.getChildSemCourses();
				for (SemesterCourses child : childrenL) {
					courseList.add(child.getCourse());
				}
				superList.add(courseList);
			}
		}
		return superList;
	}

	public List<Courses> getElectiveCourses(Curricula curr, int sem, int groupId) {
		List<Courses> courseList = new ArrayList<Courses>();
		List<SemesterCourses> sList = curr.getSemesterCourses();
		for (SemesterCourses s : sList) {
			if (s.getSemesterNo() == sem
					&& s.getCourseType() == SemesterCourses.ELECTIVE_COURSE
					&& s.getParentSemCourse() == null
					&& s.getElectiveGroup() == groupId) {
				List<SemesterCourses> childrenL = s.getChildSemCourses();
				for (SemesterCourses child : childrenL) {
					courseList.add(child.getCourse());
				}
			}
		}
		return courseList;
	}

	public List<SemesterCourses> getElectiveSemCourses(Curricula curr, int sem,
			int groupId) {
		List<SemesterCourses> courseList = new ArrayList<SemesterCourses>();
		List<SemesterCourses> sList = curr.getSemesterCourses();
		for (SemesterCourses s : sList) {
			if (s.getSemesterNo() == sem
					&& s.getCourseType() == SemesterCourses.ELECTIVE_COURSE
					&& s.getParentSemCourse() == null
					&& s.getElectiveGroup() == groupId) {
				List<SemesterCourses> childrenL = s.getChildSemCourses();
				for (SemesterCourses child : childrenL) {
					courseList.add(child);
				}
			}
		}
		return courseList;
	}

	public SemesterCourses getSemCourse(Curricula curr, int sem, int groupId,
			Courses course) {
		List<SemesterCourses> sList = curr.getSemesterCourses();
		for (SemesterCourses s : sList) {
			if (s.getSemesterNo() == sem
					&& s.getCourseType() == SemesterCourses.ELECTIVE_COURSE
					&& s.getParentSemCourse() == null
					&& s.getElectiveGroup() == groupId) {
				List<SemesterCourses> childrenL = s.getChildSemCourses();
				for (SemesterCourses child : childrenL) {
					if (child.getCourse() == course)
						return child;
				}
			}
		}
		return null;
	}

	public List<Curricula> getCurricula(Universities univ) {
		return univ.getCurricula();
	}

	public List<Curricula> getCurriculaByDept(Departments dept) {
		return dept.getCurriculums();
	}

	public Integer getNumElectives(Curricula curr, int sem) {
		int electiveCount = 0;
		List<SemesterCourses> sList = curr.getSemesterCourses();
		for (SemesterCourses s : sList) {
			if (s.getParentSemCourse() == null && s.getSemesterNo() == sem
					&& s.getCourseType() == SemesterCourses.ELECTIVE_COURSE) {
				electiveCount++;
			}
		}
		return electiveCount;
	}

	public List<Curricula> getCurrByCourse(Courses course) {
		List<SemesterCourses> sC = course.getSemesterCourses();
		List<Curricula> curr = new ArrayList<Curricula>();
		for (SemesterCourses s : sC) {
			if (!curr.contains(s.getCurricula()))
				curr.add(s.getCurricula());
		}
		return curr;
	}
	
	public void deleteCurricula(Curricula curr){
		for(int i=0;i<curr.getTotalSemester();i++){
			clearMandatoryCourses(curr,i);
			clearOptionalCourses(curr, i);
		}
		getDataContext().deleteObject(curr);
		getDataContext().commitChanges();
	}
}
